// uart_transport.cpp
#include "uart_transport.h"
#include "mdfu_errors.h"
#include <vector>
#include <iostream>

Frame::Frame(const std::vector<uint8_t> &packet) : packet(packet) {}

std::vector<uint8_t> Frame::to_bytes()
{
    std::vector<uint8_t> check_sequence = {static_cast<uint8_t>(calculate_checksum(packet) & 0xff),
                                        static_cast<uint8_t>((calculate_checksum(packet) >> 8) & 0xff)};
    packet.insert(packet.end(), check_sequence.begin(), check_sequence.end());
    std::vector<uint8_t> frame_payload = encode_payload(packet);
    // frame_payload.insert(frame_payload.end(), check_sequence.begin(), check_sequence.end());

    std::vector<uint8_t> frame;
    frame.push_back(FRAME_START_CODE);
    frame.insert(frame.end(), frame_payload.begin(), frame_payload.end());
    frame.push_back(FRAME_END_CODE);

    return frame;
}

std::vector<uint8_t> Frame::encode_payload(const std::vector<uint8_t> &data)
{
    std::vector<uint8_t> encoded;
    for (uint8_t c : data)
    {
        switch (c)
        {
        case FRAME_START_CODE:
            encoded.push_back(ESCAPE_SEQ_CODE);
            encoded.push_back(FRAME_START_ESC_SEQ[1]);
            break;
        case FRAME_END_CODE:
            encoded.push_back(ESCAPE_SEQ_CODE);
            encoded.push_back(FRAME_END_ESC_SEQ[1]);
            break;
        case ESCAPE_SEQ_CODE:
            encoded.push_back(ESCAPE_SEQ_CODE);
            encoded.push_back(ESCAPE_SEQ_ESC_SEQ[1]);
            break;
        default:
            encoded.push_back(c);
        }
    }
    return encoded;
}

unsigned short Frame::calculate_checksum(const std::vector<uint8_t> &data)
{
    unsigned int checksum = 0;
    size_t data_len = data.size();
    size_t padded_len = data_len + (data_len % 2); // Ensure even number of bytes
    for (size_t i = 0; i < padded_len; i += 2)
    {
        unsigned char low_byte = i < data_len ? static_cast<unsigned char>(data[i]) : 0;
        unsigned char high_byte = i + 1 < data_len ? static_cast<unsigned char>(data[i + 1]) : 0;
        checksum += (static_cast<unsigned int>(high_byte) << 8) | low_byte;
    }
    return static_cast<unsigned short>(~checksum & 0xFFFF);
}

// ============================== Uart_Transport ==============================

Uart_Transport::Uart_Transport(int uart_port, int baud_rate, int timeout_ms)
    : uart_port(uart_port), baud_rate(baud_rate), timeout(timeout_ms) {}

Uart_Transport::Uart_Transport() {}

// TODO 需要完成和下控板的通信，获取正确数据
std::vector<uint8_t> Uart_Transport::read(int timeout)
{
    std::vector<uint8_t> data = {0x01, 0x01, 0x03, 0x04, 0x05};
    throw MdfuErrors::TransportError("Time out"); 
    return data;
}

// TODO 修改为套接字通信
// 目前已确定需要在c++代码中实现socket的通信，但这一步考虑到linux的不同的头文件。
// 不太好在windows上测试，故这一步后续再去实现，目前先在java层面编写套接字去测试
void Uart_Transport::write(const std::vector<uint8_t> &data){
    std::vector<uint8_t> frame_data = Frame(data).to_bytes();
    std::cout << "Frame data: ";
    for (uint8_t c : frame_data)
    {
        std::cout << std::hex << (c & 0xFF) << " ";
    }
    std::cout << std::endl;
}
